"""
数据实时显示界面
"""
import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import serial
import serial.tools.list_ports
import threading
import time
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.animation import FuncAnimation
import matplotlib.gridspec as gridspec

# 设置matplotlib支持中文显示
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题


class DataVisualizer:
    def __init__(self, master):
        self.master = master
        self.master.title("60通道串口数据实时可视化")
        self.master.geometry("1200x800")
        self.master.minsize(1000, 600)

        # 数据存储
        self.channel_count = 60  # 60通道
        self.sample_count = 100  # 每个通道显示的样本数
        self.data_buffer = np.zeros((self.channel_count, self.sample_count))
        self.channel_names = [f"通道 {i + 1}" for i in range(self.channel_count)]
        # 创建主布局
        self.create_widgets()

        # 初始化图形
        self.init_figures()
        # 绑定窗口关闭事件
        self.master.protocol("WM_DELETE_WINDOW", self.on_close)

    def create_widgets(self):
        # 主框架
        self.main_frame = ttk.Frame(self.master, padding="10")
        self.main_frame.pack(fill=tk.BOTH, expand=True)

        # 数据显示区
        self.display_frame = ttk.Frame(self.main_frame)
        self.display_frame.pack(fill=tk.BOTH, expand=True)

        # 创建一个带滚动条的画布容器，用于容纳大量子图
        self.canvas_frame = ttk.Frame(self.display_frame)
        self.canvas_frame.pack(fill=tk.BOTH, expand=True)

    def init_figures(self):
        """初始化图形显示"""
        # 为了显示60通道数据，我们将其分为多个子图（10行6列）
        self.fig = plt.Figure(figsize=(12, 20), dpi=80)
        gs = gridspec.GridSpec(10, 6, figure=self.fig)  # 10行6列网格

        self.axes = []
        self.lines = []

        # 创建子图和线条对象
        for i in range(self.channel_count):
            row = i // 6  # 计算行索引
            col = i % 6  # 计算列索引
            ax = self.fig.add_subplot(gs[row, col])
            self.axes.append(ax)

            # 初始化每条线
            line, = ax.plot(self.data_buffer[i], 'b-', linewidth=0.8)
            self.lines.append(line)

            # 设置子图属性
            ax.set_title(self.channel_names[i], fontsize=8)
            ax.set_ylim(-1, 1)  # 初始范围，可根据实际数据调整
            ax.tick_params(axis='both', which='major', labelsize=6)
            ax.grid(True, linestyle='--', alpha=0.7)

        # 调整子图间距
        self.fig.tight_layout()

        # 创建Tkinter画布并添加滚动条
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.canvas_frame)
        self.canvas_widget = self.canvas.get_tk_widget()

        # 添加滚动条
        self.scrollbar_y = ttk.Scrollbar(self.canvas_frame, orient=tk.VERTICAL, command=self.canvas_widget.yview)
        self.scrollbar_x = ttk.Scrollbar(self.canvas_frame, orient=tk.HORIZONTAL, command=self.canvas_widget.xview)
        self.canvas_widget.configure(yscrollcommand=self.scrollbar_y.set, xscrollcommand=self.scrollbar_x.set)

        # 布局
        self.scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)
        self.scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)
        self.canvas_widget.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # 启动动画更新
        self.ani = FuncAnimation(
            self.fig,
            self.update_plots,
            interval=50,  # 20Hz更新频率
            blit=True
        )

    def process_data(self, data_list):
        """处理接收到的长度为60的列表数据"""
        # 检查数据长度是否正确
        if len(data_list) != self.channel_count:
            print(f"数据长度不匹配: 收到 {len(data_list)} 个点，预期 {self.channel_count} 个")
            return

        try:
            # 确保所有元素都是数值类型
            data_points = [float(x) for x in data_list]

            # 更新数据缓冲区（左移一位，添加新数据）
            self.data_buffer = np.roll(self.data_buffer, -1, axis=1)
            self.data_buffer[:, -1] = data_points

        except ValueError as e:
            print(f"数据转换错误: {str(e)}")

    def update_plots(self, frame):
        """更新图形显示"""

        for i in range(self.channel_count):
            # 更新线条数据
            self.lines[i].set_ydata(self.data_buffer[i])

            # 动态调整Y轴范围
            min_val = np.min(self.data_buffer[i])
            max_val = np.max(self.data_buffer[i])
            padding = (max_val - min_val) * 0.1 if (max_val - min_val) > 0 else 0.1
            self.axes[i].set_ylim(min_val - padding, max_val + padding)

        return self.lines  # 返回需要更新的对象

    def clear_data(self):
        """清空数据缓冲区"""
        self.data_buffer = np.zeros((self.channel_count, self.sample_count))
        # self.log_message("已清空数据缓冲区")

    def on_close(self):
        """关闭窗口时的清理工作"""
        self.master.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    app = DataVisualizer(root)
    root.mainloop()
